var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var bodyParser = require('body-parser');
var redis = require('socket.io-redis');
var os = require('os');
var cmd = require('node-cmd');
const { spawn } = require('child_process');
const child_process = require('child_process');
var db_update = require('./db_update.js');
var global_var = require('./config/global_variable.js');
var datalist = require('./cluster_config.js');
const SMSClient = require('@alicloud/sms-sdk');
var public_fun = require('./lib/public_fun.js');
//在线
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json());
app.use(express.static(__dirname + '/server_cluster'));
// dbwrap.db_init();

app.all('*', function (req, res, next){
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With,Content-Type,token,Accept");
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By", 'BIM');
    next();
});
http.listen(9066, function () {
    console.log('listening on *:9066');
});

app.get('/', function (req, res){
    res.redirect('/child_process.html');
});

// 主进程参数设置
var sys_use = null;
var timer = 5000;
function get_cpu(){
    if(sys_use == null){
        sys_use = getProcessInfo();
        setTimeout(get_cpu,timer);
        return;
    }
    var user = process.cpuUsage(sys_use.cpu).user;
    sys_use = getProcessInfo();
    var obj = {};
    obj.cpu = (user/timer/1000).toFixed(4)*100;
    var mem_per = sys_use.mem.rss;
    var mem_total = sys_use.totalmem;
    obj.mem = (mem_per/1024/1024).toFixed(2)+"MB";
    obj.mem_scale = (mem_per/mem_total).toFixed(4)*100;
    datalist['9066'].send.time = (new Date()).getTime();
   	datalist['9066'].send.memory = obj.mem;
   	datalist['9066'].send.cpu = obj.cpu;
   	datalist['9066'].send.mem_scale = obj.mem_scale;
    setTimeout(get_cpu,timer);
}
get_cpu();
// 调用创建子进程的函数(服务器名称，端口号，数据库名称)
for (var key in datalist) {
	// start：1 启动
	if(datalist[key].start == 0)
		continue;
	var port = datalist[key].send.port;
	var filename = datalist[key].filename;
	var flag = datalist[key].flag;
	datalist[key].processobj = child_process.fork(filename,[port,flag], {
	    silent: true
	});	
	var child = datalist[key].processobj;
    change_status(port,'启动中',null);
	child.stdout.on('data', (data) => {
	  console.log(`输出：${data}`);
	});

	child.stderr.on('data', (data) => {
	  console.log(`错误：${data}`);
	});
    child.on('exit', function(code, signal) {
    	// 0表示退出
    	// 杀死进程并且重新启动
    	// kill_process(child);
	　　console.log('子进程已退出'+code);
	});
	child.on('close', (code,signal) => {
	  console.log(`子进程退出码：${code}`);
	});
	child.on('error', (err) => {
	  console.log('启动子进程失败。');
      change_status(port,'失败',cd);
	});
	child.on('message', (data) => {
	  // console.log('PARENT got message:', data);
	  if (data.ret == 1) {
	  	//子进程启动成功,改变该端口进程的状态;
	  	// console.log(data.port,data.info);
	  	//保存子进程的cpu和内存使用情况
	  	change_usage(data.port,data.info);
	  }
	});
	child.send({cluster_start: 1});//父进程启动
}
//****************************磁盘容量计算***********************************
function create_process(port,filename,flag,cd){
	datalist[port].processobj = child_process.fork(filename,[port,flag], {
	    silent: true
	});	
    var child = datalist[port].processobj;
    change_status(port,'启动中',cd);
	child.stdout.on('data', (data) => {
	  console.log(`输出：${data}`);
	});
	child.stderr.on('data', (data) => {
	  console.log(`错误：${data}`);
	});
    child.on('exit', function(code, signal) {
    	// 0表示退出
    	// 杀死进程并且重新启动
    	// kill_process(child);
	　　console.log('子进程已退出'+code);
	});
	child.on('close', (code,signal) => {
	  console.log(`子进程退出码：${code}`);
	});
	child.on('error', (err) => {
	  console.log('启动子进程失败。');
      change_status(port,'失败',cd);
	});
	child.on('message', (data) => {
	  // console.log('PARENT got message:', data);
	  if (data.ret == 1) {
	  	//子进程启动成功,改变该端口进程的状态;
	  	// console.log(data.port,data.info);
	  	//保存子进程的cpu和内存使用情况
	  	change_usage(data.port,data.info);
	  }
	});
}

// ********************以下是接口******************************************
// 子进程列表
app.get('/list_process',function(req,res){   
	var obj = [];
	var cur_time = (new Date()).getTime();
	for(var key in datalist){
		datalist[key].send.cur_time = cur_time;
		obj.push(datalist[key].send);
	}
    res.send({ret:1,info:obj});
});
// 重启某个子进程
app.post('/restart_process',function(req,res){
    var title = req.body.name;
    var port = req.body.port;
    if (title == null || title == '' || port == null || port == '') {
    	res.sendStatus(501);
    	return;
    }
    var status = datalist[port].send.status;
    var processobj = datalist[port].processobj;
    var filename = datalist[port].filename;
    var flag = datalist[port].flag;
    if (status == '未启动' ) {
        create_process(port,filename,flag,function(ret,info){
  			// console.log(ret);
           res.send({ret:ret,info:info});
        });
	}else{
		if (processobj != null) {
         kill_process(processobj,port,function(ret,info){
	  	   if (ret == 1) {
		  		create_process(port,filename,flag,function(ret,info){
	                  res.send({ret:ret,info:info});
	               });
			  	}
			});
	    }else{
	    	res.send({ret:-1,info:'没有该子进程'});
	    }
	}
    
});
// 停止某个子进程
app.post('/stop_process',function(req,res){
    var title = req.body.name;
    var port = req.body.port;
    if (title == null || title == '' || port == null || port == '') {
    	res.sendStatus(501);
    	return;
    }
    var processobj = datalist[port].processobj;
    var status = datalist[port].send.status;
    if (status == '未启动') {
    	res.send({ret:1,info:"已经是未启动"});
    	return;
    }
    if (processobj != null) {
        kill_process(processobj,port,function(ret,info){
		  	res.send({ret:ret,info:info});
		});

    } else {
    	res.send({ret:-1,info:'没有该子进程'});
    }
});
// 获取ip，端口
app.post('/getip/:title',function(req,res){
    var title = req.params.title;
    if (title == null || title == '') {
    	res.sendStatus(501);
    	return;
    }
    switch(title)
		{
		case 'server_file_zdnet':
		  res.send({ip:"192.168.1.232",port:9060});
		  break;
		case 'server_file_android':
		  res.send({ip:"192.168.1.232",port:9061});
		  break;
		case 'server_instant':
		  res.send({ip:"192.168.1.232",port:8888});
		  break;
		case 'server_zdnet':
		  res.send({ip:"192.168.1.232",port:9050});
		  break;
		default:
		  res.send({msg:"没有该服务器"});
		  break;
		}
});
// 磁盘容量
//操作系统名称，基于linux的返回linux,基于苹果的返回Darwin,基于windows的返回Windows_NT
var type = os.type();
app.post('/getdisk',function(req,res){
   var node_path = process.cwd().substr(0,1);
   var disk_data = null; 
   var obj = {};
	if (type == 'Windows_NT') {
		var ls = spawn("./oshelp5.exe",[]);
		ls.stdout.on('data', (data) => {
		   disk_data = JSON.parse(`${data}`);
		   for (var i = 0; i < disk_data.length; i++) {
              if(disk_data[i].current = "1"){
                var use = Number(disk_data[i].total)-Number(disk_data[i].free);
                var total = Number(disk_data[i].total);
                obj.percent = Math.ceil((use/total).toFixed(2)*100);
                obj.disk = disk_data[i].name;
                break;
              }
            }
	       res.send({ret:1,info:obj});
		});
	}else if (type == 'linux') {
	    console.log(type);
	    free = spawn('df', ['-hl','/'+node_path]);
		// 捕获标准输出并将其打印到控制台 
		free.stdout.on('data', function (data) { 
		// console.log('standard output:\n' + data); 
		disk_data = data;
		});
		// var use =;
  //       var total =;
  //       obj.percent = Math.ceil((use/total).toFixed(2)*100);
  //       obj.disk = 
  //       res.send({ret:1,info:obj});
	}
});
// **********************数据库操作接口************************************
// 获取所有的数据库列表
app.get("/database_list",function(req,res){

});
// 删除数据库
app.post("/editdatabase/:db_name",function(req,res){

});
// 获取指定端口的数据库中的所有表
app.get("/gettables/:port",function(req,res){
    var port = req.params.port;
    if (port == null || port == '') {
    	res.sendStatus(501);
    	return;
    }
    var dbname = datalist[port].db_name;
    if (dbname == null) {
        res.send({ret:-1,info:'没有数据库'});
        return;
    };
    db_update.db_init(dbname);
    db_update.db_info_get_tables(function(ret,info){
	     // console.log(ret,info);
	     res.send({ret:ret,info:info});
	});
});
// 获取指定端口下指定表的所有字段信息
app.get("/getfields/:port/:tablename",function(req,res){
	var port = req.params.port;
	var tablename = req.params.tablename;
    if (port == null || port == '' || tablename == null || tablename == '') {
    	res.sendStatus(501);
    	return;
    }
    var dbname = datalist[port].db_name;
    db_update.db_init(dbname);
    db_update.db_info_get_fields(tablename,function(ret,info){
        // console.log(ret,info);
        res.send({ret:ret,info:info});
   });
});
// 编辑表：增加，删除
app.post("/edittable/:port/:oper",function(req,res){
	var port = req.params.port;
    var oper = req.params.oper;
    var tablename = req.body.tablename;
    if (port == null || port == '' || oper == null || oper == '') {
    	res.sendStatus(501);
    	return;
    }
    if (tablename == null || '') {
    	res.sendStatus(501);
    	return;
    }
	var dbname = datalist[port].db_name;//'shop.db'
	// 确定操作哪个数据库
	db_update.db_init(dbname);
	// 具体操作
	if (oper == 'add') {
		db_update.db_info_add_table(req.body,function(ret,info){
		     console.log(ret,info);
		     res.send({ret:ret,info:info});
		});
	}else if(oper == 'del'){
		db_update.db_info_delete_table(tablename,function(ret,info){
		     res.send({ret:ret,info:info});
		});
	}
    
});
// 编辑表中的某个字段：添加，
app.post("/editfield/:port/:oper",function(req,res){
	var port = req.params.port;
    var oper = req.params.oper;
    var tablename = req.body.tablename;
    if (port == null || port == '' || oper == null || oper == '') {
    	res.sendStatus(501);
    	return;
    }
    if (tablename == null || '') {
    	res.sendStatus(501);
    	return;
    }
	var dbname = datalist[port].db_name;//'shop.db'
	// 确定操作哪个数据库
	db_update.db_init(dbname);
    // var body = {tablename:"minyanan",fieldname:"aaa",type:'TEXT'};
    if (oper == 'add') {
    	db_update.db_info_add_field(req.body,function(ret,info){
		   console.log(ret,info);
		   res.send({ret:ret,info:info});
		});
    }
});

// ********************以下是函数******************************************

// 杀死进程
function kill_process(child,port,cd){
	// child.kill(signal='SIGTERM');
	child.kill();
	// 修改进程的状态
    change_status(port,'未启动',cd);
}
// 改变进程的状态
function change_status(port,str,cd){
	// console.log("222222");
	var find = false;
   for (var key in datalist) {
     if (datalist[key].send.port == port) {
     	datalist[key].send.status = str;
     	find = true;
     	break;
     }
   }
   if(cd !=null)
   	cd(find==true?1:0,'ok');
}
// 改变cpu和内存的使用情况
function change_usage(port,info){
	var sport = "";
	sport += port;
   	datalist[sport].send.time = (new Date()).getTime();
   	datalist[sport].send.memory = info.mem;
   	datalist[sport].send.cpu = info.cpu;
   	datalist[sport].send.mem_scale = info.mem_scale;
}

/**
 * 获取当前Node.js进程信息
 */
function getProcessInfo(){
    const memUsage = process.memoryUsage();//内存使用
    const cpuUsage = process.cpuUsage();//cpu使用
    const cfg = process.config;//编译node.js的配置信息
    const env = process.env;//用户环境
    const pwd = process.cwd();//工作目录
    const execPath = process.execPath;//node.exe目录
    const pf = process.platform;//运行nodejs的操作系统平台
    const release = process.release;//nodejs发行版本
    const pid = process.pid;//nodejs进程号
    const arch = process.arch;//运行nodejs的操作系统架构
    const uptime = process.uptime();//nodejs进程运行时间
    const totalmem = os.totalmem();
    return {
        mem:memUsage,
        cpu:cpuUsage,      
        pid:pid,
        totalmem:totalmem,
        uptime:uptime
    }
}

// 短信服务接口
// 虚拟设计院的注册验证码
app.post('/regist_xnsjy',function(req,res){
    var code = req.body.code;
    var phone = req.body.phone;
    if (code == null || phone == null) {
        res.sendStatus(404);
        return;
    }
    const accessKeyId = 'LTAImZ3YpYs5vzsG';
    const secretAccessKey = 'MqSMWJjCyJewD5fsYJIJvWHD5TLc45';
    //初始化sms_client
    let smsClient = new SMSClient({accessKeyId, secretAccessKey});
    var send_data = {
        code:code
    }
    //发送短信
    smsClient.sendSMS({
        PhoneNumbers: phone,
        SignName: '阿里云短信测试专用',
        TemplateCode: 'SMS_115385809',
        TemplateParam: JSON.stringify(send_data)
    }).then(function (data) {
        let {Code} = data
        if (Code === 'OK') {
            //处理返回参数
            res.send({ret:1,info:'ok'});
        }
    }, function (err) {
        // console.log(err)
           res.send({ret:-1,info:'invalid mobile number'}); 
    })
})
